// Actually Nino should look here: http://www.xml.com/pub/rg/XML_Parsers (!)    -- xPablo
// Actually nino can write his own ;)                                           -- Nino_a
// Actually there is NO usable xml parser...                                    -- xPablo
// despite i write my own one :P                                                -- Nino_a

#include "xml.h"

xml_object *xptr;
static char *global_path;

// Private functions
static char increment_single( char *c );
static int xml_increment_id( char * id );
static xml_object * xml_init_object( xml_object * prev, char *id, char *addr );
static int xml_last_id( char *last_id );
static void xml_free_object( xml_object * x );

void xml_init_storage( char *path ) {
  global_path = path;
    xptr = NULL;
    FILE *fp;
    if( (fp=fopen(path, "r"))==NULL ) {
        log( ERR, "Error 001: unable to open urlstorage" );
        exit( 1 );
    }
    long size;
    fseek( fp, 0, SEEK_END );
    size = ftell( fp );
    fseek( fp, 0, SEEK_SET );
    char xmlraw[size];
    char c;
    char* ptr;
  int i;
    
    for( i=0,c=getc(fp); i<size; c=getc(fp), i++ )
        xmlraw[i]=c;
    
    for( ptr=xmlraw; *ptr != 0; ptr++ ) {
        if( str_has_prefx( ptr, "<url id=\"" ) ) {
            ptr+=9; // ptr now points to the first digit of ›id‹
            
            // store the id in ›id‹
            char id[32];
            for( i=0; *ptr != '"'; i++, ptr++ ) id[i] = *ptr;
            id[i] = 0;                          //  printf( "xml_init_storage( ): id='%s'\n", id );
            ptr+=2;
            
            // store the address in ›addr‹
            char addr[2048];
            for( i=0; !str_has_prefx( ptr, "</url>\n" ); i++, ptr++ )  addr[i] = *ptr;
            addr[i] = 0;                        //  printf( "xml_init_storage( ): addr='%s'\n", addr );
            
            // malloc the struct
            if( xptr == NULL )
                xptr = xml_init_object( NULL, id, addr );
            else {
                xptr = xptr->next = xml_init_object( xptr, id, addr );
            }
        }
    }
}

static xml_object * xml_init_object( xml_object * prev, char *id, char *addr ) {
    xml_object *x = malloc( sizeof( xml_object ));
    assert( x );
    x->id = malloc( 1+ strlen( id ) * sizeof( char ) );
    strcpy( x->id, id );
    x->addr = malloc( strlen( addr ) * sizeof (char ));
    strcpy( x->addr, addr );
    x->next = NULL;
    x->prev = prev;
    return x;
}

void xml_free_db( ) {
    xml_free_object( xptr );
}

static void xml_free_object( xml_object * x ) {
    free( x->addr );
    free(   x->id  );
    if( x->prev != NULL )
        xml_free_object( x->prev );
    if( x->next != NULL )
        xml_free_object( x->next );
    free( x );
}

 /**************************************************
    * This is the old version, I don't delete it, to have a backup
    * int xml_last_id( char *xml, char *last_id ) {
    *
    *   
    *       int s_len = strlen( xml );
    *       int i, j, k; // counters
    *       
    *       for( i = s_len; i > 0; i-- ) {
    *           if( xml[ i ] == ' ' && xml[ i+1] == 'i' && xml[ i+2] == 'd' && xml[ i+3 ] == '=' ) {
    *               i += 5; // i now is the starting point of the id
    *               break;
    *           }
    *       }
    *       
    *       for( j=1; xml[ i+j ] != '"'; j++ );
    *       
    *       for( k=0; k < j; k++ )
    *           last_id[ k ] = xml[ i+k ];
    *           
    *       return 0;
    *
    *}
  ***************************************************/

static int xml_last_id( char *last_id ) {
    if( xptr == NULL )
        return -1;
    strcpy( last_id, xptr->id );
}

static char increment_single( char *c ) {

/***************************************************
 * If 0 is returned, everything went fine
 * if 1 is returned, c is set to 'a' and the next char has to be increased by one
 * if -1 is returned, it failed
 ***************************************************/
 
 if( *c >= 'a' && *c < 'z' ) {
        *c += 1;
        return 0;
    }
    else if( *c == 'z' ) {
        *c= 'A';
        return 0;
    }
    else if( *c >= 'A' && *c < 'Z' ) {
        *c += 1;
        return 0;
    }
    else if( *c == 'Z' ) {
        *c = '0';
        return 0;
    }
    else if( *c >= '0' && *c < '9' ) {
        *c += 1;
        return 0;
    }
    else if( *c == '9' ) {
        *c = 'a';
        return 1;
    }
    else {
        return -1;
    }
}

int xml_increment_id( char *id ) {
    if( !id ) return -1;
    int len, i;
    len = strlen( id );
    i = len -1;
    if( len < 1 ) return -1;
    
    while( (increment_single( &id[ i]) ) == 1 ) {
        if( i > 0 )
            i-=1;
        else {
            memset( id, 'a', (len+1) ); // haven't tested this, was ›id[len]='a';‹ before
            id[ len+1 ] = '\0';
        }
    }
    
    return 0;
}

char* xml_get_url( char *id ) {
    xml_object *ptr = xptr;
    while( strcmp( ptr->id, id ) && ptr != NULL )
        ptr = ptr->prev;
        
    if( ptr != NULL )
        return ptr->addr;
    else
        return NULL;
}

static int xml_get_id( char *xml, char *addr, char *id ) {
    if( !xml ) return -1;
    if( !addr ) return -1;
    if( !id ) return -1;
    
    int i, j, idlen, addrlen, xmllen;
    
    addrlen = strlen( addr );
    xmllen = strlen( xml );
    
    for( i=xmllen; i > 0; i-- ) {
        if( ( xml[i-2]== '"' ) &&
              ( xml[i-1]== '>' ) &&
              ( xml[ i] == addr[0] ) )
        {
            if( ( xml[ i + addrlen ] == '<' ) &&
                   ( xml[ i + addrlen + 1 ] == '/' ) )
            {
                for( j=0; xml[ i + j ] == addr[ j ]; j++ );
                if( j == addrlen ) {
                    i -= 2;
                    for( idlen=0; xml[ i - idlen - 1] != '"'; idlen++ );
                    i -= idlen;
                    for( j=0; j< idlen; j++ )
                        id[ j] = xml[ i+j ];
                }
            }
        }
    }
    if( idlen == 1 )
        id[ 1 ] = '\0';
  return 0;
}

char* xml_compress_new( char* addr ) {
    // search the db for the addr
    xml_object* ptr;
    for( ptr= xptr; ptr != NULL; ptr = ptr->prev ) {
        if( strcmp( ptr->addr, addr ) == 0 )
            return ptr->id;
    }
    xptr->next = xml_init_object( xptr, xptr->id, addr );
    xptr = xptr->next;
    xml_increment_id( xptr->id );
    
    // write data
    FILE *fp;
    if( (fp=fopen(global_path, "r+"))==NULL ) {
        log( ERR, "Error 001: unable to open urlstorage" );
        }
    fseek( fp, -12, SEEK_END );
    fprintf( fp, "\n\t<url id=\"%s\">%s</url>\n</database>", xptr->id, xptr->addr );
    fclose( fp);
    
    return( xptr->id );
}

